package com.example.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.example.dto.ApiResponse;
import com.example.entity.ExamAntiCheatingRecord;
import com.example.mapper.ExamAntiCheatingRecordMapper;
import com.example.service.ExamAntiCheatingService;
import com.example.utils.LogUtils;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * 考试防作弊服务实现类
 * 处理考试过程中的可疑行为记录和分析
 */
@Service
public class ExamAntiCheatingServiceImpl implements ExamAntiCheatingService {
    
    private static final Logger log = LoggerFactory.getLogger(ExamAntiCheatingServiceImpl.class);
    private static final String LOG_TAG = "ANTI_CHEATING";
    
    @Autowired
    private ExamAntiCheatingRecordMapper examAntiCheatingRecordMapper;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Override
    @Transactional
    public ApiResponse<?> recordSuspiciousBehavior(Long examId, Long studentId, String behaviorType, 
                                                 String behaviorDetails, String riskLevel) {
        try {
            // 验证参数
            if (examId == null || studentId == null || behaviorType == null || behaviorType.trim().isEmpty()) {
                return ApiResponse.error("参数不完整：考试ID、学生ID和行为类型不能为空");
            }
            
            // 验证行为类型
            if (!isValidBehaviorType(behaviorType)) {
                return ApiResponse.error("无效的行为类型：" + behaviorType);
            }
            
            // 验证风险等级
            if (riskLevel == null || riskLevel.trim().isEmpty()) {
                riskLevel = "MEDIUM"; // 默认中等风险
            } else if (!isValidRiskLevel(riskLevel)) {
                return ApiResponse.error("无效的风险等级：" + riskLevel);
            }
            
            // 创建可疑行为记录
            ExamAntiCheatingRecord record = new ExamAntiCheatingRecord();
            record.setExamId(examId);
            record.setStudentId(studentId);
            record.setBehaviorType(behaviorType);
            record.setBehaviorDetails(behaviorDetails);
            record.setRiskLevel(riskLevel);
            record.setRecordTime(LocalDateTime.now());
            record.setCreateTime(LocalDateTime.now());
            
            // 保存到数据库
            examAntiCheatingRecordMapper.insert(record);
            
            LogUtils.security(LOG_TAG, String.format("记录可疑行为 - 考试ID: %d, 学生ID: %d, 行为类型: %s, 风险等级: %s", 
                    examId, studentId, behaviorType, riskLevel));
            
            return ApiResponse.success("可疑行为记录成功", record);
            
        } catch (Exception e) {
            LogUtils.error(LOG_TAG, "记录可疑行为失败", e);
            return ApiResponse.error("记录可疑行为失败：" + e.getMessage());
        }
    }
    
    @Override
    public List<ExamAntiCheatingRecord> getExamSuspiciousRecords(Long examId) {
        try {
            return examAntiCheatingRecordMapper.findByExamId(examId);
        } catch (Exception e) {
            LogUtils.error(LOG_TAG, "获取考试可疑行为记录失败：examId=" + examId, e);
            return new ArrayList<>();
        }
    }
    
    @Override
    public List<ExamAntiCheatingRecord> getStudentSuspiciousRecords(Long examId, Long studentId) {
        try {
            return examAntiCheatingRecordMapper.findByExamIdAndStudentId(examId, studentId);
        } catch (Exception e) {
            LogUtils.error(LOG_TAG, String.format("获取学生可疑行为记录失败：examId=%d, studentId=%d", examId, studentId), e);
            return new ArrayList<>();
        }
    }
    
    @Override
    public Map<String, Object> getExamSuspiciousStatistics(Long examId) {
        Map<String, Object> statistics = new HashMap<>();
        
        try {
            List<ExamAntiCheatingRecord> records = examAntiCheatingRecordMapper.findByExamId(examId);
            
            // 统计总记录数
            statistics.put("totalRecords", records.size());
            
            // 按行为类型统计
            Map<String, Integer> behaviorTypeStats = new HashMap<>();
            Map<String, Integer> riskLevelStats = new HashMap<>();
            Map<Long, Integer> studentStats = new HashMap<>();
            
            for (ExamAntiCheatingRecord record : records) {
                // 行为类型统计
                behaviorTypeStats.merge(record.getBehaviorType(), 1, Integer::sum);
                
                // 风险等级统计
                riskLevelStats.merge(record.getRiskLevel(), 1, Integer::sum);
                
                // 学生统计
                studentStats.merge(record.getStudentId(), 1, Integer::sum);
            }
            
            statistics.put("behaviorTypeStats", behaviorTypeStats);
            statistics.put("riskLevelStats", riskLevelStats);
            statistics.put("studentStats", studentStats);
            
            // 高风险行为数量
            int highRiskCount = riskLevelStats.getOrDefault("HIGH", 0) + riskLevelStats.getOrDefault("CRITICAL", 0);
            statistics.put("highRiskCount", highRiskCount);
            
            // 涉及可疑行为的学生数量
            statistics.put("suspiciousStudentCount", studentStats.size());
            
        } catch (Exception e) {
            LogUtils.error(LOG_TAG, "获取考试可疑行为统计失败：examId=" + examId, e);
            statistics.put("error", "统计数据获取失败");
        }
        
        return statistics;
    }
    
    @Override
    public Map<String, Object> getStudentSuspiciousStatistics(Long examId, Long studentId) {
        Map<String, Object> statistics = new HashMap<>();
        
        try {
            List<ExamAntiCheatingRecord> records = examAntiCheatingRecordMapper.findByExamIdAndStudentId(examId, studentId);
            
            // 统计总记录数
            statistics.put("totalRecords", records.size());
            
            // 按行为类型统计
            Map<String, Integer> behaviorTypeStats = new HashMap<>();
            Map<String, Integer> riskLevelStats = new HashMap<>();
            
            for (ExamAntiCheatingRecord record : records) {
                behaviorTypeStats.merge(record.getBehaviorType(), 1, Integer::sum);
                riskLevelStats.merge(record.getRiskLevel(), 1, Integer::sum);
            }
            
            statistics.put("behaviorTypeStats", behaviorTypeStats);
            statistics.put("riskLevelStats", riskLevelStats);
            
            // 计算风险评分
            int riskScore = calculateRiskScore(riskLevelStats);
            statistics.put("riskScore", riskScore);
            
            // 最近的可疑行为
            if (!records.isEmpty()) {
                statistics.put("lastSuspiciousTime", records.get(0).getRecordTime());
            }
            
        } catch (Exception e) {
            LogUtils.error(LOG_TAG, String.format("获取学生可疑行为统计失败：examId=%d, studentId=%d", examId, studentId), e);
            statistics.put("error", "统计数据获取失败");
        }
        
        return statistics;
    }
    
    @Override
    public List<ExamAntiCheatingRecord> getSuspiciousRecordsByRiskLevel(Long examId, String riskLevel) {
        try {
            return examAntiCheatingRecordMapper.findByExamIdAndRiskLevel(examId, riskLevel);
        } catch (Exception e) {
            LogUtils.error(LOG_TAG, String.format("按风险等级获取可疑行为记录失败：examId=%d, riskLevel=%s", examId, riskLevel), e);
            return new ArrayList<>();
        }
    }
    
    @Override
    @Transactional
    public ApiResponse<?> batchRecordBehaviorCounts(Long examId, Long studentId, Map<String, Integer> behaviorCounts) {
        try {
            if (behaviorCounts == null || behaviorCounts.isEmpty()) {
                return ApiResponse.success("无可疑行为数据需要记录");
            }
            
            List<ExamAntiCheatingRecord> records = new ArrayList<>();
            LocalDateTime now = LocalDateTime.now();
            
            // 为每种行为类型创建汇总记录
            for (Map.Entry<String, Integer> entry : behaviorCounts.entrySet()) {
                String behaviorType = entry.getKey();
                Integer count = entry.getValue();
                
                if (count != null && count > 0) {
                    // 将计数字段映射为标准行为类型
                    String standardBehaviorType = mapBehaviorCountToBehaviorType(behaviorType);
                    if (standardBehaviorType != null) {
                        ExamAntiCheatingRecord record = new ExamAntiCheatingRecord();
                        record.setExamId(examId);
                        record.setStudentId(studentId);
                        record.setBehaviorType(standardBehaviorType);
                        record.setBehaviorDetails(String.format("{\"count\": %d, \"source\": \"exam_submission\"}", count));
                        record.setRiskLevel(calculateRiskLevelByCount(standardBehaviorType, count));
                        record.setRecordTime(now);
                        record.setCreateTime(now);
                        
                        records.add(record);
                    }
                }
            }
            
            // 批量插入记录
            if (!records.isEmpty()) {
                for (ExamAntiCheatingRecord record : records) {
                    examAntiCheatingRecordMapper.insert(record);
                }
                
                LogUtils.security(LOG_TAG, String.format("批量记录考试提交可疑行为 - 考试ID: %d, 学生ID: %d, 记录数: %d", 
                        examId, studentId, records.size()));
            }
            
            return ApiResponse.success("批量记录可疑行为完成", records);
            
        } catch (Exception e) {
            LogUtils.error(LOG_TAG, "批量记录可疑行为失败", e);
            return ApiResponse.error("批量记录可疑行为失败：" + e.getMessage());
        }
    }
    
    /**
     * 验证行为类型是否有效
     */
    private boolean isValidBehaviorType(String behaviorType) {
        return behaviorType != null && (
                "KEYBOARD_SHORTCUT".equals(behaviorType) ||
                "COPY_PASTE".equals(behaviorType) ||
                "TAB_SWITCH".equals(behaviorType) ||
                "MOUSE_LEAVE".equals(behaviorType) ||
                "FULLSCREEN_EXIT".equals(behaviorType) ||
                "WINDOW_FOCUS_LOSS".equals(behaviorType)
        );
    }
    
    /**
     * 验证风险等级是否有效
     */
    private boolean isValidRiskLevel(String riskLevel) {
        return riskLevel != null && (
                "LOW".equals(riskLevel) ||
                "MEDIUM".equals(riskLevel) ||
                "HIGH".equals(riskLevel) ||
                "CRITICAL".equals(riskLevel)
        );
    }
    
    /**
     * 将前端提交的计数字段映射为标准行为类型
     */
    private String mapBehaviorCountToBehaviorType(String countField) {
        switch (countField) {
            case "keyboard_shortcut_count":
                return "KEYBOARD_SHORTCUT";
            case "copy_paste_count":
                return "COPY_PASTE";
            case "tab_switch_count":
                return "TAB_SWITCH";
            default:
                return null;
        }
    }
    
    /**
     * 根据行为类型和计数计算风险等级
     */
    private String calculateRiskLevelByCount(String behaviorType, Integer count) {
        if (count == null || count <= 0) {
            return "LOW";
        }
        
        switch (behaviorType) {
            case "KEYBOARD_SHORTCUT":
                if (count >= 10) return "CRITICAL";
                if (count >= 5) return "HIGH";
                if (count >= 2) return "MEDIUM";
                return "LOW";
                
            case "COPY_PASTE":
                if (count >= 5) return "CRITICAL";
                if (count >= 3) return "HIGH";
                if (count >= 1) return "MEDIUM";
                return "LOW";
                
            case "TAB_SWITCH":
                if (count >= 8) return "CRITICAL";
                if (count >= 4) return "HIGH";
                if (count >= 2) return "MEDIUM";
                return "LOW";
                
            default:
                return "MEDIUM";
        }
    }
    
    /**
     * 计算风险评分
     */
    private int calculateRiskScore(Map<String, Integer> riskLevelStats) {
        int score = 0;
        score += riskLevelStats.getOrDefault("LOW", 0) * 1;
        score += riskLevelStats.getOrDefault("MEDIUM", 0) * 3;
        score += riskLevelStats.getOrDefault("HIGH", 0) * 7;
        score += riskLevelStats.getOrDefault("CRITICAL", 0) * 15;
        return score;
    }
} 